#include <Windows.h>
#include <stdio.h>
#include <stdint.h>
#include <winternl.h>

typedef LONG(__stdcall* NtCreateSection_t)(HANDLE*, ULONG, void*, LARGE_INTEGER*, ULONG, ULONG, HANDLE);
typedef LONG(__stdcall* NtMapViewOfSection_t)(HANDLE, HANDLE, PVOID*, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, DWORD, ULONG, ULONG);

int32_t wmain(int32_t nArgc, const wchar_t* pArgv[]) {
	printf("... current PID: %d\r\n", GetCurrentProcessId());
	//HMODULE hMod = LoadLibraryA("user32.dll");
	const char* HookDllPath = "ScytheHookDll64.dll";
	
	HMODULE hMod = LoadLibraryA(HookDllPath);
	if (hMod) {
		printf("... successfully loaded hook DLL %s to 0x%p\r\n", HookDllPath, hMod);
	}
	else {
		printf("... failed to load hook DLL %s (error 0x%08x)\r\n", HookDllPath, GetLastError());
	}
	system("pause");
	//if (nArgc < 2) {
	//	printf("... usage: %ws <PID>\r\n", pArgv[0]);
	//}
	//else {
		uint32_t dwPid = nArgc == 2 ? _wtoi(pArgv[1]) : 0;
		HANDLE hProcess;

		if (!dwPid) {
			STARTUPINFOW StartupInfo = { 0 };
			PROCESS_INFORMATION ProcInfo = { 0 };
			wchar_t CommandLine[MAX_PATH + 1] = { 0 };

			StartupInfo.cb = sizeof(StartupInfo);
			wcscpy_s(CommandLine, MAX_PATH + 1, L"RemoteDummy64.exe");

			if (CreateProcessW(nullptr, CommandLine, nullptr, nullptr, false, DETACHED_PROCESS, nullptr, nullptr, &StartupInfo, &ProcInfo)) {
				printf("... successfully launched protected process (PID %d)\r\n", ProcInfo.dwProcessId);
				dwPid = ProcInfo.dwProcessId;
			}
			else {
				printf("... failed to launch protected process\r\n");
			}
		}

		system("pause");

		printf("... opening handle to PID %d... ", dwPid);

		if ((hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwPid)) != NULL) {
			uint8_t* pPrivateRegion = NULL;
			uint8_t* pMappedRegion = NULL;
			uint8_t* pImageRegion = NULL;

			printf("success.\r\n");
			printf("... allocating remote private region... ");

			if ((pPrivateRegion = (uint8_t*)VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) != NULL) {
				printf("success: 0x%p\r\n", pPrivateRegion);
			}
			else {
				printf("failed (error %d)\r\n", GetLastError());
			}

			printf("... mapping remote mapped region from the page file... ");

			NtCreateSection_t NtCreateSection;
			NtMapViewOfSection_t NtMapViewOfSection;
			HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
			LARGE_INTEGER SectionMaxSize = { 0,0 };
			HANDLE hSection;
			size_t cbViewSize = 0;
			NTSTATUS NtStatus;

			NtCreateSection = (NtCreateSection_t)GetProcAddress(hNtdll, "NtCreateSection");
			NtMapViewOfSection = (NtMapViewOfSection_t)GetProcAddress(hNtdll, "NtMapViewOfSection");
			SectionMaxSize.LowPart = 0x1000;

			NtStatus = NtCreateSection(
				&hSection,
				SECTION_MAP_EXECUTE | SECTION_MAP_READ | SECTION_MAP_WRITE, // Protections up to the point of mapping a view of the section will not allow VirtualProtect modifications inconsistent with their initial allocation
				NULL, &SectionMaxSize,
				PAGE_EXECUTE_READWRITE,
				SEC_COMMIT,
				NULL);

			if (NT_SUCCESS(NtStatus)) {
				NtMapViewOfSection(hSection, hProcess, (void**)&pMappedRegion, 0, 0, NULL, (PSIZE_T)&cbViewSize, 2, 0, PAGE_EXECUTE_READWRITE); // This is more than an initial protection. Setting as +RW causes setting any +X on a region within the view to fail

				if (NT_SUCCESS(NtStatus)) {
					printf("success: 0x%p\r\n", pMappedRegion);
				}
				else {
					printf("failed (error 0x%08x)\r\n", NtStatus);
				}
			}

			wchar_t SelfPath[MAX_PATH + 1] = { 0 };
			HANDLE hFile;
			
			hSection = NULL;
			cbViewSize = 0;
			GetModuleFileNameW(NULL, SelfPath, MAX_PATH + 1);
			hFile = CreateFileW(SelfPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

			if (hFile != INVALID_HANDLE_VALUE) {
				printf("... successfully opened handle to self at %ws\r\n", SelfPath);
				printf("... mapping remote image region from %ws... ", SelfPath);
				NtStatus = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL, PAGE_READONLY, SEC_IMAGE, hFile);

				if (NT_SUCCESS(NtStatus)) {
					NtStatus = NtMapViewOfSection(hSection, hProcess, (void**)&pImageRegion, 0, 0, NULL, (PSIZE_T)&cbViewSize, 1, 0, PAGE_READONLY); // AllocationType of MEM_COMMIT|MEM_RESERVE is not needed for SEC_IMAGE.

					if (NT_SUCCESS(NtStatus)) {
						printf("success: 0x%p\r\n", pImageRegion);
					}
					else {
						printf("NtMapViewOfSection failed (error 0x%08x)\r\n", NtStatus);
					}
				}
				else {
					printf("NtCreateSection failed (error 0x%08x)\r\n", NtStatus);
				}
			}
			else {
				printf("... failed to open handle to self at %ws\r\n", SelfPath);
			}
		}
		else {
			printf("failed (error %d)\r\n", GetLastError());
		}
	//}

	system("pause");
	return 0;
}